#include "icache/deinterlaced_footage.h"
#include "icache/deinterlaced_item_id.h"
#include "icache/cache.h"
#include "xml/stream.h"

namespace icache {

string deinterlaced_footage::filepath() const 
{
	return supplier_->filepath();
}

deinterlaced_item_id_sptr deinterlaced_footage::frame_id_core(int frame)
{
	bool uf = fields_ == fields_upper_first;
	bool even = (frame % 2) == 0;
	return deinterlaced_item_id_sptr(new deinterlaced_item_id(
		*supplier_->cache(),
		supplier_->frame_id(frame/2),
		uf ? even : !even,
		method_));
}

item_id_sptr deinterlaced_footage::frame_id(int frame)
{
	return frame_id_core(frame);
}

cached_image_sptr deinterlaced_footage::get(int frame, nearby may_be_requested_later, bool wait)
{
	bool disturb_suplier = false;
	cached_image_sptr r = try_get(frame);
	if (!r)
		disturb_suplier = true;
	if (!disturb_suplier && (may_be_requested_later & backward) && frame >= 2)
		disturb_suplier = !try_get(frame-2);
	if (!disturb_suplier && (may_be_requested_later & forward) && frame+2 < size())
		disturb_suplier = !try_get(frame+2);
	if (r && !disturb_suplier)
		return r;

	cached_image_sptr p = supplier_->get(frame/2, may_be_requested_later, wait);
	if (wait && !r) {
		assert(p);
		deinterlaced_item_id_sptr id = frame_id_core(frame);
		r = cached_image::create(id);
		id->deinterlace(p->im, r->im);
		cache()->put(r);
	}
	return r;
}

cached_image_sptr deinterlaced_footage::try_get(int frame)
{
	return cache()->try_get(frame_id(frame));
}

icache::cache * deinterlaced_footage::cache() const
{
	return supplier_->cache(); //this requirement comes from deinterlaced_item_id
}

xml::stream & deinterlaced_footage::serialize(xml::stream & s, string const & reference_path)
{
	using namespace xml;

	xml::node & r = s.root();
	if (s.out())
		r["type"] = "dil";
	else
		if ((string)r["type"] != "dil")
			throw exception("couldn't initialize Deinterlaced Footage from XML stream");

	s || attr("field", fields_);
	if (fields_ == fields_off)
		throw exception("bad value of deinterlace field value");

	s || attr("method", method_);

	if (s.out())
		supplier_->serialize(s.child("supplier"), reference_path);
	//supplier_ read is located in panel class
	return s;
}

string deinterlaced_footage::description() const
{
	return supplier_->description();
}

int deinterlaced_footage::size() const
{
	return supplier_->size() * 2;
}

int deinterlaced_footage::first_frame_num() const
{
	return supplier_->first_frame_num();
}

size_extent deinterlaced_footage::dim() const
{
	return supplier_->dim();
}

bool deinterlaced_footage::alpha_channel() const
{
	return supplier_->alpha_channel();
}

void deinterlaced_footage::set_deinterlace_fields(deinterlace_fields value)
{
	if (value != fields_off)
		fields_ = value;
}

deinterlace_fields deinterlaced_footage::get_deinterlace_fields() const
{
	return fields_;
}

void deinterlaced_footage::set_deinterlace_method(deinterlace_method value)
{
	method_ = value;
}

deinterlace_method deinterlaced_footage::get_deinterlace_method() const
{
	return method_;
}

fraction deinterlaced_footage::fps() const
{
	fraction frac = supplier_->fps();
	return fraction(frac.num * 2, frac.den);
}

deinterlaced_footage::deinterlaced_footage(footage_sptr const & supplier) : supplier_(supplier)
{
	assert(supplier_);
	if (supplier_->deinterlaced())
		throw exception("nested deinterlacing is not allowed");
}

deinterlaced_footage::deinterlaced_footage(footage_sptr const & supplier, deinterlace_fields f, deinterlace_method m) :
	supplier_(supplier), fields_(f), method_(m)
{
	assert(supplier_);
	assert(fields_ != fields_off);
	if (supplier_->deinterlaced())
		throw exception("nested deinterlacing is not allowed");
}

deinterlaced_footage::~deinterlaced_footage()
{
}

footage_sptr deinterlaced_footage::create(
	deinterlace_fields field, deinterlace_method method,
	footage_sptr const & supplier)
{
	if (field == fields_off)
		return supplier;
	else
		return footage_sptr(new deinterlaced_footage(supplier, field, method));
}

} //namespace icache
